Understanding UITableView and UICollectionView in iOS Development
Course: iOS App Development
Topic: Understanding UITableView and UICollectionView
Course Link: iOS App Development Training
Demo Link: Register for a Course Demo
JustAcademy Homepage: Visit JustAcademy
1. Introduction
UITableView and UICollectionView are important UIKit components used to display collections of data in iOS applications. They support scrolling, reusable cells, user interaction, and dynamic content updates.
UITableView is commonly used for vertically arranged rows, such as contact lists, settings, messages, and task lists. UICollectionView supports more flexible layouts, including grids, horizontal carousels, galleries, and customized arrangements of items.
Learning Objectives
- Understand the purpose of table views and collection views.
- Learn the roles of data sources, delegates, cells, and layouts.
- Create and configure reusable cells in UIKit.
- Display dynamic data using arrays and model objects.
- Handle selection, deletion, and other user interactions.
- Understand custom layouts, performance, accessibility, and troubleshooting.
2. What Is UITableView?
UITableView is a UIKit view that presents data in a single column of rows. Each row is represented by a reusable UITableViewCell. Rows can be grouped into sections, and each section can optionally have a header and footer.
Common Use Cases
- Contact lists and address books.
- Chat conversations and notification lists.
- Settings screens and menu options.
- Shopping cart items and order histories.
- Task lists and records fetched from a database.
Main Components of UITableView
| Component |
Purpose |
UITableView |
Displays rows and manages scrolling. |
UITableViewCell |
Displays the content of an individual row. |
UITableViewDataSource |
Provides the number of sections, rows, and configured cells. |
UITableViewDelegate |
Handles selection, row heights, display events, and other interactions. |
IndexPath |
Identifies a row using its section and row positions. |
| Section header and footer |
Provide labels or supplementary information for a section. |
3. What Is UICollectionView?
UICollectionView is a UIKit component that displays items using a configurable layout. Unlike a table view's standard single-column structure, a collection view can arrange items vertically, horizontally, in grids, or in more advanced layouts.
Common Use Cases
- Photo galleries and image grids.
- Product catalogs and shopping categories.
- Horizontal cards and featured-content carousels.
- Video thumbnails and media libraries.
- Dashboards, calendars, and custom item arrangements.
Main Components of UICollectionView
| Component |
Purpose |
UICollectionView |
Displays and manages a collection of items. |
UICollectionViewCell |
Displays the content of an individual item. |
UICollectionViewDataSource |
Provides sections, item counts, and cells. |
UICollectionViewDelegate |
Handles selection and other item interactions. |
UICollectionViewLayout |
Defines the positions and arrangement of items. |
UICollectionViewFlowLayout |
Arranges items in a configurable flow of rows or columns. |
| Supplementary views |
Display section headers, footers, or related information. |
4. UITableView vs. UICollectionView
| Feature |
UITableView |
UICollectionView |
| Default presentation |
Single-column rows. |
Items arranged by a layout. |
| Layout flexibility |
Best suited to row-based lists. |
Supports grids, carousels, and custom layouts. |
| Cell class |
UITableViewCell |
UICollectionViewCell |
| Data source methods |
Uses row counts and row cell configuration. |
Uses item counts and item cell configuration. |
| Layout configuration |
Uses row heights, separators, and table styles. |
Uses a collection view layout object. |
| Typical examples |
Messages, contacts, settings. |
Photos, products, card grids. |
Both components support reusable cells, scrolling, sections, selection, and dynamic updates. Choose based on the desired presentation rather than assuming one is always faster or better.
5. Understanding Data Sources and Delegates
UIKit separates data management from presentation. A data source supplies the content that a list or collection displays, while a delegate responds to interactions and presentation-related events.
UITableViewDataSource
Common methods include:
numberOfSections(in:) — returns the number of sections.
tableView(_:numberOfRowsInSection:) — returns the number of rows in a section.
tableView(_:cellForRowAt:) — configures and returns a reusable cell.
UITableViewDelegate
Common responsibilities include responding to row selection, configuring row heights, and handling display events.
UICollectionViewDataSource
Common methods include:
numberOfSections(in:) — returns the number of sections.
collectionView(_:numberOfItemsInSection:) — returns the number of items in a section.
collectionView(_:cellForItemAt:) — configures and returns a reusable cell.
UICollectionViewDelegate
Common responsibilities include handling item selection and coordinating interactions with collection view cells.
6. Creating a UITableView in a UIKit Project
A table view can be added through a storyboard or created programmatically. The following example creates a simple list using Swift and UIKit.
Step 1: Create a View Controller
import UIKit
final class FruitListViewController: UIViewController,
UITableViewDataSource,
UITableViewDelegate {
private let tableView = UITableView(
frame: .zero,
style: .plain
)
private let fruits = [
"Apple",
"Banana",
"Orange",
"Mango",
"Grapes"
]
override func viewDidLoad() {
super.viewDidLoad()
title = "Fruits"
view.backgroundColor = .systemBackground
tableView.dataSource = self
tableView.delegate = self
tableView.register(
UITableViewCell.self,
forCellReuseIdentifier: "FruitCell"
)
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.topAnchor
),
tableView.leadingAnchor.constraint(
equalTo: view.leadingAnchor
),
tableView.trailingAnchor.constraint(
equalTo: view.trailingAnchor
),
tableView.bottomAnchor.constraint(
equalTo: view.bottomAnchor
)
])
}
func tableView(
_ tableView: UITableView,
numberOfRowsInSection section: Int
) -> Int {
return fruits.count
}
func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath
) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: "FruitCell",
for: indexPath
)
var content = cell.defaultContentConfiguration()
content.text = fruits[indexPath.row]
cell.contentConfiguration = content
return cell
}
func tableView(
_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath
) {
let fruit = fruits[indexPath.row]
print("Selected fruit: \(fruit)")
tableView.deselectRow(
at: indexPath,
animated: true
)
}
}
Explanation
- The view controller creates a table view and an array of fruit names.
- The table view's data source and delegate are assigned to the controller.
- A cell class is registered with a reuse identifier.
- The data source reports the number of rows and configures each cell.
- The delegate handles row selection.
This example assumes the view controller is presented by the app's navigation or view-controller setup. The table view itself can be used without a navigation controller.
7. Understanding Cell Reuse in UITableView
Table views reuse cell objects as rows move offscreen. Instead of allocating a new cell for every row, UIKit can recycle an existing cell and configure it for new data. This reduces memory use and improves scrolling performance.
The method dequeueReusableCell(withIdentifier:for:) retrieves a reusable cell for the requested index path. Register the cell class or nib before dequeuing it.
Best Practices for Cell Reuse
- Use stable, meaningful reuse identifiers.
- Configure all relevant cell content each time a cell is requested.
- Reset old asynchronous image or loading state when necessary.
- Avoid expensive processing inside the cell configuration method.
- Do not assume a cell permanently represents the same data item.
8. Creating a UICollectionView
A collection view requires a layout that defines how items are arranged. The following example creates a simple two-column grid using UICollectionViewFlowLayout.
Step 1: Configure the Collection View
import UIKit
final class FruitGridViewController: UIViewController,
UICollectionViewDataSource,
UICollectionViewDelegate {
private var collectionView: UICollectionView!
private let fruits = [
"Apple",
"Banana",
"Orange",
"Mango",
"Grapes",
"Peach"
]
override func viewDidLoad() {
super.viewDidLoad()
title = "Fruit Gallery"
view.backgroundColor = .systemBackground
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 8
layout.minimumLineSpacing = 8
layout.sectionInset = UIEdgeInsets(
top: 12,
left: 12,
bottom: 12,
right: 12
)
collectionView = UICollectionView(
frame: .zero,
collectionViewLayout: layout
)
collectionView.backgroundColor = .systemBackground
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(
UICollectionViewCell.self,
forCellWithReuseIdentifier: "FruitCell"
)
view.addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.topAnchor
),
collectionView.leadingAnchor.constraint(
equalTo: view.leadingAnchor
),
collectionView.trailingAnchor.constraint(
equalTo: view.trailingAnchor
),
collectionView.bottomAnchor.constraint(
equalTo: view.bottomAnchor
)
])
}
func collectionView(
_ collectionView: UICollectionView,
numberOfItemsInSection section: Int
) -> Int {
return fruits.count
}
func collectionView(
_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath
) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: "FruitCell",
for: indexPath
)
var label = cell.contentView.viewWithTag(100)
as? UILabel
if label == nil {
let newLabel = UILabel()
newLabel.tag = 100
newLabel.textAlignment = .center
newLabel.numberOfLines = 0
newLabel.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(newLabel)
NSLayoutConstraint.activate([
newLabel.topAnchor.constraint(
equalTo: cell.contentView.topAnchor,
constant: 8
),
newLabel.leadingAnchor.constraint(
equalTo: cell.contentView.leadingAnchor,
constant: 4
),
newLabel.trailingAnchor.constraint(
equalTo: cell.contentView.trailingAnchor,
constant: -4
),
newLabel.bottomAnchor.constraint(
equalTo: cell.contentView.bottomAnchor,
constant: -8
)
])
label = newLabel
}
label?.text = fruits[indexPath.item]
cell.contentView.backgroundColor = .secondarySystemBackground
cell.contentView.layer.cornerRadius = 10
return cell
}
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath
) -> CGSize {
let spacing: CGFloat = 8
let inset: CGFloat = 12
let availableWidth = collectionView.bounds.width
- (inset * 2)
- spacing
return CGSize(
width: floor(availableWidth / 2),
height: 100
)
}
func collectionView(
_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath
) {
print("Selected fruit: \(fruits[indexPath.item])")
}
}
extension FruitGridViewController:
UICollectionViewDelegateFlowLayout {}
Important: This example uses a basic reusable cell to demonstrate the layout and data source. For a production app, create a custom UICollectionViewCell subclass or use a cell registration so the cell's views are configured cleanly and only once.
9. Understanding UICollectionView Layouts
The layout object determines the size and position of collection view cells and supplementary views. It is separate from the data source, which supplies the actual content.
UICollectionViewFlowLayout
UICollectionViewFlowLayout arranges items in a flowing sequence. Items fill a row or column and wrap to the next line when space is limited.
Important properties include:
itemSize — the default size of items.
minimumLineSpacing — the minimum spacing between rows or columns.
minimumInteritemSpacing — the minimum spacing between items in a line.
sectionInset — spacing around the content of a section.
scrollDirection — sets horizontal or vertical scrolling.
headerReferenceSize and footerReferenceSize — specify supplementary header and footer sizes.
Horizontal Carousel Example
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 180, height: 120)
layout.minimumLineSpacing = 12
layout.sectionInset = UIEdgeInsets(
top: 8,
left: 16,
bottom: 8,
right: 16
)
This layout can be used for featured products, recommended articles, or horizontally scrolling cards.
Compositional Layout
UICollectionViewCompositionalLayout supports more advanced layouts built from sections, groups, and items. It is useful for interfaces that combine a large featured card, horizontal carousels, and standard grids on the same screen.
10. Creating Custom Cells
Default cells are useful for simple content, but custom cells provide better control over design and behavior. A custom cell can contain labels, images, buttons, badges, and other views.
Example Custom Table View Cell
import UIKit
final class ContactTableViewCell: UITableViewCell {
private let nameLabel = UILabel()
private let emailLabel = UILabel()
override init(
style: UITableViewCell.CellStyle,
reuseIdentifier: String?
) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
nameLabel.font = .preferredFont(forTextStyle: .headline)
emailLabel.font = .preferredFont(forTextStyle: .subheadline)
emailLabel.textColor = .secondaryLabel
let stack = UIStackView(
arrangedSubviews: [nameLabel, emailLabel]
)
stack.axis = .vertical
stack.spacing = 4
stack.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(stack)
NSLayoutConstraint.activate([
stack.topAnchor.constraint(
equalTo: contentView.topAnchor,
constant: 10
),
stack.leadingAnchor.constraint(
equalTo: contentView.leadingAnchor,
constant: 16
),
stack.trailingAnchor.constraint(
equalTo: contentView.trailingAnchor,
constant: -16
),
stack.bottomAnchor.constraint(
equalTo: contentView.bottomAnchor,
constant: -10
)
])
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func configure(name: String, email: String) {
nameLabel.text = name
emailLabel.text = email
}
}
Register the custom cell class with the table view, dequeue it in the data source, and call configure(name:email:) using the data associated with the requested index path.
11. Displaying Model Objects
Real applications usually display model objects rather than hard-coded strings. A model groups related properties into a meaningful data structure.
struct Contact {
let id: UUID
var name: String
var email: String
}
let contacts = [
Contact(
id: UUID(),
name: "Aarav Sharma",
email: "[email protected]"
),
Contact(
id: UUID(),
name: "Maya Patel",
email: "[email protected]"
)
]
In a table view, the data source can use contacts[indexPath.row] to configure the cell. In a collection view, it can use contacts[indexPath.item]. A stable ID helps identify an item even when the array is sorted or modified.
12. Handling Selection and User Interaction
Table and collection views provide delegate methods for responding when a user selects an item. Selection can navigate to a detail screen, display a preview, or trigger another action.
Table View Selection
func tableView(
_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath
) {
let selectedItem = fruits[indexPath.row]
print("Selected: \(selectedItem)")
tableView.deselectRow(at: indexPath, animated: true)
}
Collection View Selection
func collectionView(
_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath
) {
let selectedItem = fruits[indexPath.item]
print("Selected: \(selectedItem)")
}
For navigation, pass the selected model object or its stable identifier to the destination view controller. Avoid relying on a row number as a permanent identity because sorting, insertion, and deletion can change index paths.
13. Adding and Deleting Rows or Items
When the data changes, the visible list or collection must be updated to match the underlying data source. Update the model first, then update the UI consistently.
Insert a Table View Row
fruits.insert("Pineapple", at: 0)
tableView.insertRows(
at: [IndexPath(row: 0, section: 0)],
with: .automatic
)
This example assumes the data source is backed by the same mutable array and the insertion index is valid. The number of rows reported by the data source must agree with the table view's updates.
Delete a Table View Row
let indexPath = IndexPath(row: 0, section: 0)
fruits.remove(at: indexPath.row)
tableView.deleteRows(
at: [indexPath],
with: .automatic
)
The array in this example must be declared with var, not let, because it is modified. In a full implementation, confirm the index path is valid and update the data model before calling the corresponding table view update.
Reloading Data
tableView.reloadData()
collectionView.reloadData()
reloadData() refreshes the displayed content from the current data source. It is convenient for simple cases, but targeted insertions, deletions, or diffable data source snapshots can provide smoother updates and clearer state management.
14. Using Diffable Data Sources
Diffable data sources provide an identifier-based way to update list and collection interfaces. Instead of manually coordinating every insertion, deletion, and movement, the app creates a snapshot representing the desired sections and items and applies it to the data source.
Both UITableViewDiffableDataSource and UICollectionViewDiffableDataSource support this pattern. Use unique, stable item identifiers and ensure that the snapshot represents the correct current state of the data.
Conceptual Workflow
- Create a diffable data source and provide a cell provider.
- Create a snapshot for the section and item identifier types.
- Append the sections to the snapshot.
- Append the item identifiers to the relevant section.
- Apply the snapshot to display the updated state.
Diffable data sources are particularly helpful when data changes frequently, when items move between sections, or when the app needs animated updates without manually managing index-path differences.
15. Section Headers and Footers
Sections group related rows or items. For example, a contacts list may group people by category, while a product gallery may separate products by department.
- For a table view, use the relevant data source methods or header and footer views to provide section labels.
- For a collection view, register and provide supplementary views such as headers and footers, and configure the layout to allocate space for them.
- Use clear section names and maintain a logical grouping structure.
16. Loading Images and Remote Data
Collection views and table views often display images loaded from disk or a remote server. Image loading should not block the main thread.
- Use asynchronous networking for remote image requests.
- Cache downloaded images where appropriate.
- Display a placeholder while an image loads.
- Account for cell reuse so an old image does not appear in the wrong row or item.
- Cancel or ignore obsolete requests when a cell is reused.
- Use prefetching when early data preparation can improve scrolling performance.
For production apps, use a well-designed image-loading layer or an appropriate caching library rather than placing all networking logic directly inside cell configuration methods.
17. Performance Optimization
- Reuse cells instead of allocating new cells for every item.
- Keep cell configuration fast and predictable.
- Use stable identifiers when managing changing data.
- Prefer targeted updates or diffable data source snapshots for suitable use cases.
- Use self-sizing cells carefully and provide appropriate layout constraints.
- Load images and other expensive content asynchronously.
- Use prefetching for data that is expensive to prepare.
- Measure scrolling performance with Instruments and test on realistic devices and data volumes.
18. Accessibility and Dynamic Type
Accessible list and grid interfaces allow more people to use an application effectively.
- Use readable text sizes and support Dynamic Type where appropriate.
- Give meaningful accessibility labels to icon-only buttons.
- Ensure cells and controls have suitable accessibility traits.
- Do not communicate status only through color; include text or another clear indicator.
- Provide sufficient contrast and comfortable touch targets.
- Test with VoiceOver and larger accessibility text sizes.
19. Common Errors and Troubleshooting
| Problem |
Possible Cause |
Solution |
| Cells do not appear. |
Incorrect constraints, frame, or data source configuration. |
Verify layout constraints, registration, and data source assignments. |
| App crashes while dequeuing a cell. |
Missing registration or incorrect reuse identifier. |
Register the correct cell class or nib and use the matching identifier. |
| Wrong data appears in a cell. |
Cell content was not fully reconfigured after reuse. |
Assign every relevant content property when configuring the cell. |
| Row counts become inconsistent. |
The model and table updates are out of sync. |
Update the data source consistently with row insertions and deletions. |
| Grid items have unexpected sizes. |
Incorrect layout configuration or item-size calculation. |
Check section insets, spacing, available width, and layout invalidation. |
| Scrolling stutters. |
Expensive cell configuration or synchronous image loading. |
Move expensive work off the main thread and optimize cell setup. |
| Selection opens the wrong detail screen. |
The code relies on an outdated index path. |
Resolve the selected item's stable identifier from the current model. |
20. Practical Project: Contacts and Photo Gallery
Build a small application with two screens to practice both components.
Screen 1: Contacts List
- Display contacts in a
UITableView.
- Show the contact's name and email.
- Open a detail screen when a row is selected.
- Add, edit, and delete contacts.
- Display a helpful empty state when no contacts exist.
Screen 2: Photo Gallery
- Display images in a
UICollectionView.
- Use a grid layout with suitable spacing.
- Open a larger preview when an image is selected.
- Support loading placeholders and asynchronous image retrieval.
- Experiment with a horizontal carousel layout.
Suggested Development Plan
- Create model structures for contacts and gallery items.
- Implement the table view data source and delegate.
- Implement a reusable custom table view cell.
- Implement the collection view and its layout.
- Add navigation and selection handling.
- Implement model updates and UI refreshes.
- Test empty, large, and changing datasets.
- Check accessibility and scrolling performance.
21. Best Practices
- Choose
UITableView for straightforward row-based content and UICollectionView when layout flexibility is needed.
- Separate data models from view controllers where practical.
- Keep cell configuration reusable and focused.
- Use stable item identifiers for changing datasets.
- Update the model and visible UI consistently.
- Handle asynchronous image loading safely with cell reuse.
- Prefer appropriate modern APIs, including diffable data sources, for complex updates.
- Test selection, deletion, accessibility, and dynamic content changes.
22. Interview Questions and Answers
Q1. What is UITableView?
UITableView is a UIKit component that displays data in a single column of reusable rows, optionally grouped into sections.
Q2. What is UICollectionView?
UICollectionView displays items using a configurable layout, supporting grids, carousels, and custom arrangements.
Q3. What is the role of a data source?
The data source provides the number of sections and items or rows and configures the cells that display the data.
Q4. What is the difference between a data source and a delegate?
The data source supplies content, while the delegate handles interactions and other behavior such as selection and layout-related events.
Q5. Why are reusable cells important?
Reusable cells reduce unnecessary view creation, helping manage memory and maintain smooth scrolling.
Q6. What is IndexPath?
An IndexPath identifies an item's position. In a table view it commonly represents a section and row; in a collection view it represents a section and item.
Q7. What is UICollectionViewFlowLayout?
It is a layout class that arranges collection view items in rows or columns with configurable item sizes, spacing, and section insets.
Q8. When should a collection view be preferred?
Use it when the interface requires a grid, horizontal carousel, or other flexible layout that is difficult to represent with a standard table view.
Q9. What is a diffable data source?
It manages list or collection updates using unique item identifiers and snapshots describing the desired UI state.
Q10. How can list scrolling performance be improved?
Reuse cells, keep configuration fast, load images asynchronously, use suitable layouts, and measure performance with development tools.
23. Practice Exercises
- Create a table view displaying a list of books with titles and authors.
- Add section headers to group books by category.
- Create a collection view showing product cards in a two-column grid.
- Change the collection view to a horizontal carousel.
- Implement selection and navigate to a detail screen.
- Add a delete action to a table view and keep the data source consistent.
- Build a custom cell containing an image, title, and subtitle.
- Replace manual updates with a diffable data source.
- Test the screens with large text settings and VoiceOver.
24. Quick Revision Checklist
UITableView displays single-column rows.
UICollectionView displays items using a configurable layout.
- Data sources provide content and configure reusable cells.
- Delegates handle selection and related interactions.
- Cells should be reused and configured consistently.
- Collection view layouts determine item positions and sizes.
- Stable identifiers and consistent model updates help prevent UI errors.
- Asynchronous loading, prefetching, and efficient configuration improve performance.
25. Conclusion
UITableView and UICollectionView are fundamental UIKit tools for creating data-driven iOS interfaces. Table views are well suited to structured row-based lists, while collection views provide greater flexibility for grids, carousels, and custom arrangements. Understanding data sources, delegates, reusable cells, layouts, and update strategies helps developers create interfaces that are responsive, maintainable, and accessible.
Continue learning with JustAcademy's iOS App Development Course, register for a course demo, or visit the JustAcademy homepage.